#ifndef CSUPBR_LIGHT_H
#define CSUPBR_LIGHT_H

#include "primitive.h"

namespace csupbr {
    
    struct Shape;
    struct SkyBoxShader;
    struct Scene;

    struct VisiilityTest {
        VisiilityTest(const Intersection &spit, const Intersection &liit)
            : sp_isct(spit), li_isct(liit) {}

        bool is_occluded(std::shared_ptr<Scene>scene) const;

        Intersection sp_isct, li_isct;
    };

    struct LightRecord {
        VisiilityTest visibility;
        Vec3f wi;
    };

    struct Light {
        Light(std::shared_ptr<Transform>l2o, const Spectrum &li)
             : l2o(l2o), o2l(l2o->inverseRef()), li(li) {}
        virtual Spectrum sample_li(LightRecord &lRec, const Intersection &spit,
                                   const Point2f &sample, Float& pdf) const = 0;
        std::shared_ptr<Transform> l2o, o2l;
        Spectrum li;
    };

    // SkyBox Light 
    struct SkyLight : Light {
        explicit SkyLight(std::shared_ptr<Transform> l2o, const Spectrum &li,
                          std::shared_ptr<SkyBoxShader> shader);
        Spectrum sample_li(LightRecord &lRec, const Intersection &spit,
                           const Point2f &sample, Float &pdf) const override;
    };

    // Directional Light
    struct DirectLight : Light {
        explicit DirectLight(std::shared_ptr<Transform> l2o, const Spectrum &li,
                             const Vec3f &direct)
            : Light(l2o, li), direct(direct) {}
        Spectrum sample_li(LightRecord &lRec, const Intersection &spit,
                           const Point2f &sample, Float &pdf) const override;
        Vec3f direct;
    };

    struct PointLight : Light {
        explicit PointLight(std::shared_ptr<Transform> l2o, const Spectrum &li)
            : Light(l2o, li){}
        Spectrum sample_li(LightRecord &lRec, const Intersection &spit,
                           const Point2f &sample, Float &pdf) const override;
    };

    struct DiffuseAreaLight : Light {
        explicit DiffuseAreaLight(std::shared_ptr<Transform> l2o, const Spectrum &li,
                                  std::shared_ptr<Shape> shape)
            : Light(l2o, li), shape(shape) {}
        Spectrum sample_li(LightRecord &lRec, const Intersection &spit,
                           const Point2f &sample, Float &pdf) const override;
        std::shared_ptr<Shape> shape;
    };

}

#endif // !CSUPBR_LIGHT_H